/** Timeless - resource.h
 *
 * @author Jennifer Evers
 */
#ifndef __RESOURCELESS__
#define __RESOURCELESS__

/// Let's get everything loaded first. 
#define WIN32_LEAN_AND_MEAN

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <map>
#include <list>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>

#include <SDL/SDL.h>
#include <SDL/SDL_main.h>
#include <SDL/SDL_opengl.h>
#include <SDL/SDL_video.h>

using namespace std;

#define AUTO_SIZE unsigned long size() { return sizeof(*this); }

#define SETTING(type, target, var, name) target=new SimpleForm<type>(var); \
        register(std::string(name),Thinglike<NoForm>(target));


/// Classes.

/**
 * Thing - a base class to manage memory through.
 *
 */
class Thing {
    private:
        static std::list<Thing *> activeThings;
        static std::list<Thing *> deadThings;
        long refCount;
        
    protected:
        Thing();
        virtual ~Thing();
        
    public:
        void add();
        void remove();
        static void garbageCollector();
        static void goingDown();
        virtual unsigned long size() = 0;
};

/**
 * Thinglike - a pointer template for Things.
 */
template<class T>
class Thinglike {
    protected:
        T* obj;
        
    public:
        Thinglike::Thinglike() {
            obj = 0;
        }

        Thinglike::Thinglike(T *o) {
            obj = 0;
            *this = o;
        }

        Thinglike::Thinglike(const Thinglike<T> &p) {
            obj = 0;
            *this = p;
        }

        Thinglike::~Thinglike() {
            if( obj )
                obj->remove();
        }
        
        inline void operator =(T *o) {
            if( obj )
                obj->remove();
            obj = o;
            if( obj );
                obj->add();
        }
        
        inline void operator =(const Thinglike<T> &p) {
            if( obj )
                obj->remove();
            obj = p.obj;
            if( obj )
                obj->add();
        }
        
        inline T& operator *() const {
            assert( obj != 0 && "Tried to * on a NULL Thinglike." );
            return *obj;
        }
        
        inline T* operator ->() const {
            assert( obj != 0 && "Tried to -> on a NULL Thinglike." );
            return obj;
        }
        
        inline operator T*() const {
            return obj;
        }
        
        inline bool isValid() const {
            return( obj != 0 );
        }
        
        inline bool operator !() {
            return !(obj);
        }
        
        inline bool operator ==(const Thinglike<T> &p) const {
            return ( obj == p.obj );
        }
        
        inline bool operator ==(const T* o) const {
            return ( obj == o );
        }
};

/**
 * Chunk - a chunk of data, what else?
 */
template<class T, int i>
class Chunk : public Thing {
    protected:
        T buffer[i];
    
    public:
        inline T& operator [](int index) {
            assert( index < i && "Bad index on Chunk::[]");
            return buffer[index];
        }
        
        inline operator T*() {
            return buffer;
        }
        
        AUTO_SIZE;
};

template<class T>
class FlexChunk : public Thing {
    protected:
        unsigned long dataSize;
        T *buffer;
    
    public:
        inline T& operator [](int index) {
            assert( index < dataSize && "Bad index on FlexChunk::[]" );
            return buffer[index];
        }
        
        inline operator T*() {
            return buffer;
        }
        
        FlexChunk(unsigned long size) {
            dataSize = size;
            buffer = new T[size];
            assert( buffer != 0 && "FlexChunk couldn't create buffer." );
        }
        
        ~FlexChunk() {
            if( buffer )
                delete[] buffer;
        }
        
        unsigned long size() {
            return dataSize + sizeof(this);
        }
        
        unsigned long chunkSize() {
            return dataSize;
        }
};

/**
 * Movement - function wrappers for actions.      
 */
class Movement : public Thing {
    public:
        virtual void operator ()() = 0;
};

template<class T>
class ClassMovement : public Movement {
    protected:
        T *obj;
        typedef void (T::*funcType)();
        funcType func;
        
    public:
        AUTO_SIZE;
        
        ClassMovement(T *o, funcType f) {
            obj = o;
            func = f;
        }
        
        void operator ()() {
            (obj->*func)();
        }
};

/**
 * Unique - a singleton class with a better name.
 */
template<typename T>
class Unique {
    static T* uniqued;
    
    public:
        Unique() {
            assert( !uniqued );
            uniqued = (T*)((int)this);
        }
        
        ~Unique() {
            assert( uniqued );
            uniqued = 0;
        }
        
        static T& get() {
            assert( uniqued );
            return *uniqued;
        }
        
        static T* getPointer() {
            assert( uniqued );
            return uniqued;
        }
};

template<typename T> T* Unique<T>::uniqued = 0;

/**
 * LazySusan - a circular buffer.
 */
template<class T, unsigned long bufSize>
class LazySusan {
    protected:
        T buffer[bufSize];
        unsigned long read, write;
        
    public:
        LazySusan() {
            read = 0;
            write = 1;
        }
        
        bool operator << (T &obj) {
            buffer[write] = obj;
            ++write;
            while( write >= bufSize )
                write -= bufSize;
            
            if( write == read ) {
                --write;
                while( write < 0 )
                    write += bufSize;
                return false;
            }
            
            return true;
        }
        
        bool operator >> (T &res) {
            ++read;
            while( read >= bufSize )
                read -= bufSize;
            
            if( read == write ) {
                ++write;
                while( write >= bufSize )
                    write -= bufSize;
                return false;
            }
            
            res = buffer[read];
            return true;
        }
        
        unsigned long dataSize() {
            unsigned long wc = write;
            while( wc < read ) 
                wc += bufSize;
            return wc - read - 1;
        }
        
        void flood( const T &value ) {
            read = 0;
            for( write = 0; write < bufSize; ++write ) {
                buffer[write] = value;
            }
            write = 1;
        }
};

/**
 * NoForm - the base Thing data chunk class.
 */
class NoForm : public Thing {
    protected:
        NoForm() { }
        NoForm(NoForm &d) {
            (*this) = d;
        }
        
    public:
        virtual NoForm &operator =(std::string &input) = 0;
        virtual NoForm &operator +=(std::string &input) = 0;
        virtual NoForm &operator -=(std::string &input) = 0;
        virtual bool operator ==(std::string &input) = 0;
        virtual bool operator !=(std::string &input) = 0;
        
        virtual bool hasMany() = 0;
        
        virtual operator std::string() = 0;
};

/**
 * SimpleForm - it's like NoForm, but std::stringified.
 */
template<class T>
class SimpleForm : public NoForm {
    protected:
        T& target;
        T toVal(std::string &s) {
            std::stringstream str;
            str.unsetf(std::ios::skipws);
            str << s;
            T res;
            str >> res;
            return res;
        }
        
        std::string toString(T &val) {
            std::stringstream str;
            str.unsetf(std::ios::skipws);
            str << val;
            std::string res;
            str >> res;
            return res;
        }
    
    public:
        SimpleForm(T& t) : target(t) {}
        SimpleForm &operator =(std::string &input) {
            target = toVal(input);
            return *this;
        }
        
        SimpleForm &operator +=(std::string &input) {
            target += toVal(input);
            return *this;
        }
        
        SimpleForm &operator -=(std::string &input) {
            target -= toVal(input);
            return *this;
        }
        
        bool operator ==(std::string &input) {
            return ( input == (std::string)(*this) );
        }
        
        bool operator !=(std::string &input) {
            return ( input != (std::string)(*this) );
        }
        
        operator std::string() {
            return toString(target);
        }
        
        bool hasMany() {
            return false;
        }
        
        AUTO_SIZE;
};

/**
 * Preferences - the storage facility for all preferences/settings.
 */
class Preferences : public Unique<Preferences> {
    public:
        Preferences();
        virtual ~Preferences();
        
        void registerVar(std::string &name, Thinglike<NoForm> &var);
        void set(std::string &name, std::string &value, int bias = 0);
        void defaultSettings();
        void destroySettings();
        void parseLine( std::string str );
        void parseFile( std::string filename );
    
    protected:
        std::map<std::string, Thinglike<NoForm> > settingMap;
 };
 
 /**
  * Action - a managed task for the kernel.
  */
 class Action : public Thing {
    public:
        Action() {
            canKill = false;
            priority = 5000;
        }
        
        virtual bool start() = 0;
        virtual void onSleep() {
        }
        
        virtual void update() = 0;
        virtual void onWake() {
        }
        
        virtual void stop() = 0;
        
        bool canKill;
        long priority;
};

/**
 * GameKernel - gee, I wonder.
 */
class GameKernel : public Unique<GameKernel> {
    public:
        GameKernel();
        virtual ~GameKernel();
        
        int exec();
        
        bool addTask(Thinglike<Action> &a);
        void sleepTask(Thinglike<Action> &a);
        void wakeTask(Thinglike<Action> &a);
        void removeTask(Thinglike<Action> &a);
        void cleanTasks();
        
    protected:
        std::list<Thinglike<Action> > activeTasks;
        std::list<Thinglike<Action> > sleepingTasks;
};

class GameApplication : public Unique<GameApplication> {
    public:
        void Run( int argc, char *argv[] );
};

#endif /* __RESOURCELESS__ */
